Neste documento será realizada a Análise Exploratória de Dados (EDA) da base REDD utilizando a biblioteca NILMTK.
Convertendo os dados originais da base REDD em arquivo compatível (hdf5, contendo medições e metadata) com a NILMTK. Vale ressaltar que será considerado neste documento apenas as leituras de baixa frequência.
In [1]:
from nilmtk.dataset_converters import convert_redd
convert_redd('datasets/REDD/low_freq', 'datasets/REDD/low_freq.h5')
In [2]:
from nilmtk import DataSet
from nilmtk.utils import print_dict
redd = DataSet('datasets/REDD/low_freq.h5')
Primeiramente, é possível acessar os metadados do dataset, incluindo as informações sobre os dois modelos de medidores utilizados para a coleta dos dados:
In [3]:
print_dict(redd.metadata)
É possível também acessar informações das residências em um objeto do tipo OrderedDict (indexado a partir de 1 porque todo dataset no NILMTK inicia o índice de buildings
em 1 e não 0)
In [4]:
print_dict(redd.buildings)
Cara residência possui algumas informações de metadata:
In [5]:
print_dict(redd.buildings[1].metadata)
Ainda, cada residência possui um atributo elec
que é o objeto MeterGroup
(de fato, os medidores do tipo plug
utilizado na mediçção de cada um dos dispositivos contemplados):
In [7]:
redd.buildings[1].elec
Out[7]:
Note que há dois objetos MeterGroups
aninhados: um para o forno elétrico, e um para a secadora (ambos são dispositivos de 240 vol e possuem dois medidores por aparelho, dada a voltagem dos mesmos):
In [9]:
elec = redd.buildings[1].elec
elec.nested_metergroups()
Out[9]:
Colocar estes medidores em um objeto do tipo MeterGroup
permite facilmente somar a demanda de energia registrada por ambos os medidores a fim de capturar a demanda total de energia para o dispositivo (mas é também muito fácil ver a demanda de energia individual registrada).
É fácil acessar um MeterGroup
de submedidores (medição no nível de dispositivos) ou da(s) corrente(s) principais (mains):
In [10]:
elec.mains()
Out[10]:
Neste caso, é possível capturar os dados de energia de ambas as correntes principais somadas:
In [11]:
elec.mains().power_series_all_data().head()
Out[11]:
No caso das medições individuais dos dispositivos:
In [13]:
elec.submeters()
Out[13]:
Vamos verificar a proporção de energia submedida na residência 1:
In [15]:
elec.proportion_of_energy_submetered()
Out[15]:
In [17]:
mains = elec.mains() # Correntes principais
mains.available_ac_types('power')
Out[17]:
In [18]:
elec.submeters().available_ac_types('power') # Dispositivos
Out[18]:
In [19]:
next(elec.load()) # Verificando os dispositivos
Out[19]:
In [21]:
elec.mains().total_energy() # kWh
Out[21]:
In [22]:
energy_per_meter = elec.submeters().energy_per_meter() # kWh, again
energy_per_meter
Out[22]:
NOTA: o cabeçalho se refere aos números de instância dos objetos
ElecMeter
.
In [23]:
# energy_per_meter é um DataFrame onde cada linha é um
# tipo de energia ('active', 'reactive' or 'apparent').
# Todos os medidores de dispositivo na base REDD registros
# do tipo 'active', então basta selecionar a linha 'active':
energy_per_meter = energy_per_meter.loc['active']
more_than_20 = energy_per_meter[energy_per_meter > 20]
more_than_20
Out[23]:
In [24]:
instances = more_than_20.index
instances
Out[24]:
In [31]:
from matplotlib import rcParams
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
rcParams['figure.figsize'] = (13, 10)
# Calculando proporção individual
fraction = elec.submeters().fraction_per_meter().dropna()
In [32]:
# Criando rótulos
labels = elec.get_labels(fraction.index)
# Plotando o gráfico
plt.figure(figsize=(10,30))
fraction.plot(kind='pie', labels=labels);
In [33]:
elec.draw_wiring_graph()
Out[33]:
Não é muito evidente, mas este diagrama mostra que os medidores (1, 2 - medidores das plantas) estão a montante de todos os outros medidores.
Residências da base REDD têm apenas dois níveis na sua 'hierarquia' de medidores (correntes principais - mains - e dispositivos individuais - submeters). Se houvessem mais que dois níveis, então seria útil obter apenas os medidores imediatamente a jusante de mains:
In [34]:
elec.meters_directly_downstream_of_mains()
Out[34]:
In [35]:
#sns.set_palette("Set3", n_colors=12)
# Set a threshold to remove residual power noise when devices are off
elec.plot_when_on(on_power_threshold = 40)
Out[35]:
A classe ElecMeter
represente um medidor de eletricidade único.
Cada ElecMeter
possui uma lista de objetos Appliance
(dispositivos) associados.
ElecMeter
possui muitos dos mesmos métodos estatísticos do MeterGroup
tais como total_energy
e available_power_ac_types
and power_series
and power_series_all_data
.
Vamos explorar mais algumas funções estatísticas...
In [38]:
fridge_meter = elec['fridge'] # Dados de medição do forno elétrico
In [39]:
fridge_meter.upstream_meter()
Out[39]:
In [40]:
fridge_meter.device
Out[40]:
In [41]:
fridge_meter.total_energy() # kWh
Out[41]:
Se visualizarmos os dados de energia originais, poderemos observar que há um grande gap onde, supostamente, o medidor associado a este dispositivo parou de funcionar (vale ressaltar que, se aumentarmos o zoom, poderemos observar pequenos intervalos com este mesmo comportamento):
In [43]:
fridge_meter.plot()
Out[43]:
Podemos automaticamente identificar 'good sections' (i.e. seções onde cada par de amostras consecutivas é menor que o valor de max_sample_period
especificado no metadata do dataset):
In [44]:
good_sections = fridge_meter.good_sections(full_results=True)
# full_results=False nos dá uma lista dimples de TimeFrames.
# Mas queremos todos GoodSectionsResults para que seja possível plotar as 'good sections'...
good_sections.plot()
Out[44]:
Os blocos mostram onde os dados são 'bons' (good). O gap branco é o largo intervalo em branco visto nos dados originais.
É possível também listar as 'good sections':
In [47]:
good_sections.combined()
Out[47]:
Usamos ElecMeter.select_using_appliances()
para selecionar um novo MeterGroup usando um campo metadata.
Por exemplo, para pegar todas as máquinas secadores no dataset REDD (considerenado todas residências), fasemos o seguinte:
In [48]:
import nilmtk
nilmtk.global_meter_group.select_using_appliances(type='washer dryer')
Out[48]:
Ou selecionamos múltiplos dispositivos pelo tipo:
In [50]:
elec.select_using_appliances(type=['fridge', 'microwave'])
Out[50]:
Ou então pela categoria dos dispositivos (por exemplo, os aquecedores):
In [51]:
nilmtk.global_meter_group.select_using_appliances(category='heating')
Out[51]:
Usamos o marcador []
para retornar um único dispositivo (objeto ElecMeter
) de um MeterGroup
.
In [53]:
elec['fridge']
Out[53]:
In [54]:
elec.select_using_appliances(type='fridge')
Out[54]:
In [55]:
elec['light', 2]
Out[55]:
In [56]:
redd.set_window(start='2011-04-21', end='2011-04-22')
elec.plot();
plt.xlabel("Time");
In [61]:
import pandas as pd
from pandas.plotting import autocorrelation_plot
elec.mains().plot_autocorrelation() # Correntes principais
Out[61]:
In [64]:
fridges_restricted = nilmtk.global_meter_group.select_using_appliances(type='fridge')
daily_energy = pd.Series([meter.average_energy_per_period(offset_alias='D')
for meter in fridges_restricted.meters])
# daily_energy.plot(kind='hist');
# plt.title('Histogram of daily fridge energy');
# plt.xlabel('energy (kWh)');
# plt.ylabel('occurences');
# plt.legend().set_visible(False)
daily_energy
Out[64]:
In [65]:
correlation_df = elec.pairwise_correlation()
correlation_df
Out[65]:
In [ ]: